/*
Copyright (C) Ariff Ehsan, Abdul Hadi Fikri

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

/*  Author : Ariff Ehsan
 *           Abdul Hadi Fikri
 *  Date   : June 22, 2009
 */


#include <system.h>
#include <serial0/ports/atmega644p/atmega644p_usart0.h>

/**
*Interface Usart0{
*	Provide{
*		command void AT644P_USART0_init(void);                         @DRIVER_USART0_INIT();
*		command void AT644P_USART0_reg(void (*sendDone)(void), 
*									   void (*receive)(uint8_t data)); @DRIVER_USART0_REG(x,y);
*		error_t AT644P_USART0_send(uint8_t data)					   @DRIVER_USART0_SEND(x);
*	}
*	Uses{
*		signal void (*at644p_usart0_sendDone)(void);
*		signal void (*at644p_usart0_receive)(uint8_t data);
*   }
*}
*/

/**
 * Data Field:
 */		BOOL atmega644p_usart0_send_busy;
		uint8_t atmega644p_usart0_pend_data;

		void (*atmega644p_usart0_sendDone)(void);
		void (*atmega644p_usart0_receive)(uint8_t data);
/**
 * Field Data:
 */		void ATMEGA644P_USART0_defaultSendDone(void);
		void ATMEGA644P_USART0_defaultReceive(uint8_t);

/********************************************************************************************/
/*                                  Clients Function Call                                   */
/********************************************************************************************/
void ATMEGA644P_USART0_init(void) {
	uint16_t baud = MYUBRR0;
	
	atmega644p_usart0_send_busy = FALSE;

	atmega644p_usart0_sendDone = ATMEGA644P_USART0_defaultSendDone;
	atmega644p_usart0_receive = ATMEGA644P_USART0_defaultReceive;

	/* Set baud rate */
	UBRR0H = (unsigned char)(baud>>8);
	UBRR0L = (unsigned char)baud;

	/* Enable receiver and transmitter and interrupt*/
	UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<TXCIE0)|(1<<RXCIE0);
 
	/* Set frame format: 8data, 1stop bit */
	UCSR0C = (3<<UCSZ00);
}

void ATMEGA644P_USART0_reg(void (*sendDone)(void), void (*receive)(uint8_t data)) {
  if (sendDone != NULL) {
	  atmega644p_usart0_sendDone = sendDone;
	}

	if (receive != NULL) {
	  atmega644p_usart0_receive = receive;
	}
}

error_t ATMEGA644P_USART0_send(uint8_t data) {
	if (atmega644p_usart0_send_busy) {
		return EBUSY;
	}

	atmega644p_usart0_send_busy = TRUE;
  
	if (!( UCSR0A & (1<<UDRE0) )) {
		atmega644p_usart0_pend_data = data;
    
		// enable UDRE interrupt
		UCSR0B |= (1<<UDRIE0);

		return SUCCESS;
	}

	UDR0 = data;

	return SUCCESS;
}

/********************************************************************************************/
/*                                 Internal Function Call                                   */
/********************************************************************************************/
void ATMEGA644P_USART0_defaultSendDone(void) {
}

void ATMEGA644P_USART0_defaultReceive(uint8_t data) {
}
/********************************************************************************************/
/*                              HW/SW Interrupt Function Call                               */
/********************************************************************************************/
/**
 *  ISR UDRE
 */
ISR(USART0_UDRE_vect) {
  
  // disable UDRE interrupt
  CLR_BIT(UCSR0B, UDRIE0);
  UDR0 = atmega644p_usart0_pend_data;

}
/**
 *  ISR TRANSMIT
 */
ISR(USART0_TX_vect) {

  atmega644p_usart0_send_busy = FALSE;
  (*atmega644p_usart0_sendDone)();

}
/**
 *  ISR RECEIVE
 */
ISR(USART0_RX_vect) {

  uint8_t data = UDR0;
  (*atmega644p_usart0_receive)(data);

}



